/*
 * Copyright (c) 2024, sakumisu
 *
 * SPDX-License-Identifier: Apache-2.0
 */
#include "usbd_core.h"
#include "usbd_hid.h"

/*!< endpoint address */
#define HID_INT_EP          0x81
#define HID_INT_EP_SIZE     4
#define HID_INT_EP_INTERVAL 1

#define USBD_VID           0xffff
#define USBD_PID           0xffff
#define USBD_MAX_POWER     100
#define USBD_LANGID_STRING 1033

/*!< config descriptor size */
#define USB_HID_CONFIG_DESC_SIZ 34
/*!< report descriptor size */
#define HID_MOUSE_REPORT_DESC_SIZE 74

/*!< global descriptor */
const uint8_t hid_descriptor[] = {
//Device Descriptor UPS-Partner V1.1005
//Offset Field Size Value Description 
//0 bLength 1 12 //  
//1 bDescriptorType 1 01 // Device 
//2 bcdUSB 2 0110 // USB Spec 1.1 
//4 bDeviceClass 1 00 // Class info in Ifc Descriptors 
//5 bDeviceSubClass 1 00 //  
//6 bDeviceProtocol 1 00 //  
//7 bMaxPacketSize0 1 08 // 8 bytes 
//8 idVendor 2 0463 //  
//10 idProduct 2 FFFFh  
//12 bcdDevice 2 0100 // 1.00 
//14 iManufacturer 1 01 // "HDR" 
//15 iProduct 1 02 // "UPS-Partner V1.1005" 
//16 iSerialNumber 1 03 // "0123456789" 
//17 bNumConfigurations 1 01 // 
0x12    
,0x01    
,0x10,0x01 
,0x00    
,0x00    
,0x00    
,0x40    
,0x63,0x04  
,0xFF,0x0F  
,0x00,0x01
,0x01   
,0x02    
,0x03    
,0x01  
//Configuration Descriptor 1 Bus Powered, 200 mA
//Offset Field Size Value Description 
//0 bLength 1 09 //  
//1 bDescriptorType 1 02 // Configuration 
//2 wTotalLength 2 0022 //  
//4 bNumInterfaces 1 01 //  
//5 bConfigurationValue 1 01 //  
//6 iConfiguration 1 00 //  
//7 bmAttributes 1 A0 // Bus Powered, Remote Wakeup 
// 4..0: Reserved  ...00000   
// 5: Remote Wakeup  ..1.....  Yes 
// 6: Self Powered  .0......  No, Bus Powered 
// 7: Reserved (set to one)
//(bus-powered for 1.0)  1.......   
//8 bMaxPower 1 64 // 200 mA 
,0x09
,0x02
,0x22,0x00
,0x01
,0x01
,0x00
,0xA0
,0x64
//Interface Descriptor 0/0 HID, 1 Endpoint
//Offset Field Size Value Description 
//0 bLength 1 09h 
//1 bDescriptorType 1 04h Interface
//2 bInterfaceNumber 1 00h 
//3 bAlternateSetting 1 00h 
//4 bNumEndpoints 1 01h 
//5 bInterfaceClass 1 03h HID
//6 bInterfaceSubClass 1 01h Boot Interface
//7 bInterfaceProtocol 1 00h 
//8 iInterface 1 00h 
,0x09
,0x04
,0x00
,0x00
,0x01
,0x03
,0x01
,0x00
,0x00
//HID Descriptor 
//Offset Field Size Value Description 
//0 bLength 1 ,0x09 = 
//1 bDescriptorType 1 ,0x21 =HID 
//2 bcdHID 2 ,0x0110 =1.10 
//4 bCountryCode 1 ,0x00 = 
//5 bNumDescriptors 1 ,0x01 = 
//6 bDescriptorType 1 ,0x22 =Report 
//7 wDescriptorLength 2 ,0x039E =926 bytes 
,0x09
,0x21
,0x10,0x01
,0x00
,0x01
,0x22
,0x9E,0x03
//Endpoint Descriptor 81 1 In, Interrupt, 20 ms
//Offset Field Size Value Description 
//0 bLength 1 ,0x07 = 
//1 bDescriptorType 1 ,0x05 =Endpoint 
//2 bEndpointAddress 1 ,0x81 =1 In 
//3 bmAttributes 1 ,0x03 =Interrupt 
// 1..0: Transfer Type  ......11  Interrupt 
// 7..2: Reserved  000000..   
//4 wMaxPacketSize 2 ,0x0008 =8 bytes 
//6 bInterval 1 ,0x14 =20 ms 
,0x07
,0x05
,0x81
,0x03
,0x08,0x00
,0x14

///////////////////////////////////////
/// string0 descriptor
///////////////////////////////////////
,USB_LANGID_INIT(0x0409),
///////////////////////////////////////
/// string1 descriptor       "HDR" 
///////////////////////////////////////
3*2+2,                       /* bLength */
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
'H', 0x00,                  /* wcChar0 */
'D', 0x00,                  /* wcChar1 */
'R', 0x00,                  /* wcChar2 */
///////////////////////////////////////
/// string2 descriptor  "UPS-Partner V1.1005" 
///////////////////////////////////////
19*2+2,                       /* bLength */
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
'U', 0x00,                  /* wcChar0 */
'P', 0x00,                  /* wcChar1 */
'S', 0x00,                  /* wcChar2 */
'-', 0x00,                  /* wcChar3 */
'P', 0x00,                  /* wcChar4 */
'a', 0x00,                  /* wcChar5 */
'r', 0x00,                  /* wcChar6 */
't',0x00,                  /* wcChar7 */
'n',0x00,                  /* wcChar8 */
'e',0x00,                  /* wcChar9 */
'r',0x00,                  /* wcChar10 */
' ',0x00,                  /* wcChar11 */
'V',0x00,                  /* wcChar12 */
'1',0x00,                  /* wcChar13 */
'.',0x00,                  /* wcChar14 */
'1',0x00,                  /* wcChar15 */
'0',0x00,                  /* wcChar16 */
'0',0x00,                  /* wcChar17 */
'5',0x00,                  /* wcChar18 */
///////////////////////////////////////
/// string3 descriptor
///////////////////////////////////////
10*2+2,                       /* bLength */
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
'0', 0x00,                  /* wcChar0 */
'1', 0x00,                  /* wcChar1 */
'2', 0x00,                  /* wcChar2 */
'3', 0x00,                  /* wcChar3 */
'4', 0x00,                  /* wcChar4 */
'5', 0x00,                  /* wcChar5 */
'6', 0x00,                  /* wcChar6 */
'7', 0x00,                  /* wcChar7 */
'8', 0x00,                  /* wcChar8 */
'9', 0x00,                  /* wcChar9 */
///////////////////////////////////////
/// string4 descriptor
///////////////////////////////////////
 0x82
,0x80
,0xEF
,0xF2
,0xEF
,0xE9
,0x93
,0x87
,0x81
,0x8B
,0x23
,0xAC
,0xF1
,0x84
,0x09
,0x47
,0x98
,0xA7
,0x37
,0x07
,0x00
,0x20
,0x93
,0x06
,0x47
,0x06
,0x23
,0xAE
,0xD1
,0x84
,0xB7
,0x07
,0x00
,0x20
,0x93
,0x87
,0x47
,0x0B
,0x23
,0xA0
,0xF1
,0x86
,0x83
,0x27
,0x47
,0x06
,0x82
,0x97
,0x6F
,0xF0
,0x4F
,0xE9
,0xEF
,0xF2
,0x4F
,0xE4
,0x41
,0x11
,0x37
,0x0A
,0x00
,0x20
,0xB7
,0x0A
,0x00
,0x20
,0xE1
,0x79
,0x23
,0x17
,0x01
,0x00
,0x13
,0x0A
,0xCA
,0x02
,0x93
,0x8A
,0x8A
,0x04
,0x93
,0x89
,0x09
,0x08
,0xB7
,0x65
,0x00
,0x40
,0x83
,0xA7
,0x45
,0xC4
,0x13
,0x97
,0x07
,0x01
,0x41
,0x83
,0x23
,0x9C
,0xE1
,0x86
,0x13
,0x97
,0x07
,0x01
,0x63
,0x57
,0x07
,0x16
,0x83
,0xD7
,0x81
,0x87
,0x3A
,0x84
,0xBD
,0x8B
,0x23
,0x8B
,0xF1
,0x84
,0x93
,0x86
,0x05
,0xC0
,0x63
,0x96
,0x07
,0x30
,0x03
,0xA7
,0x05
,0xC0
,0x93
,0x87
,0x61
,0x86
,0x42
,0x07
,0x41
,0x83
,0x9A
,0xA3
,0x9A
,0x23
,0x93
,0x86
,0x81
,0x86
,0x13
,0x77
,0x07
,0x03
,0x9A
,0xA2
,0x9A
,0x23
,0x8D
,0x66
,0x21
,0x66
,0x75
,0x8F
,0x9A
,0xA3
,0x03
,0xA7
,0x05
,0xC0
,0xA5
,0x67
,0x93
,0x87
,0xF7
,0xFB
,0x7D
,0x8F
,0x83
,0xA7
,0x05
,0xC0
,0xB1
,0x66
,0x93
,0x86
,0xF6
,0xF8
,0xF5
,0x8F
,0x89
,0x66
,0xB5
,0x8F
,0x13
,0x47
,0x07
,0x02
,0x93
,0x16
,0x07
,0x01
,0x13
,0x06
,0x06
,0x08
,0x5D
,0x8F
,0x51
,0x8F
,0xC1
,0x82
,0x23
,0xA0
,0xE5
,0xC0
,0x33
,0xE7
,0x36
,0x01
,0x42
,0x07
,0x93
,0x84
,0x61
,0x86
,0x13
,0x89
,0x81
,0x86
,0x37
,0x66
,0x00
,0x40
,0x93
,0x05
,0x00
,0x02
,0x41
,0x83
,0x83
,0x26
,0x06
,0xC0
,0x93
,0xF6
,0x06
,0x03
,0x63
,0x93
,0xB6
,0x0E
,0xB3
,0xE7
,0x37
,0x01
,0xC1
,0x66

//////
,0x00
};

/*!< hid mouse report descriptor */
static const uint8_t hid_mouse_report_desc[] = {
 0x05,0x84
,0x09,0x04
,0xA1,0x01
,0x09,0x10
,0xA1,0x00
,0x09,0x12
,0xA1,0x00
,0x09,0x5A
,0x85,0x20
,0x75,0x08
,0x95,0x01
,0x15,0x00
,0x26,0xFF,0x00
,0x65,0x00
,0x55,0x00
,0xB1,0x82
,0xC0
,0x09,0x14
,0xA1,0x00
,0x09,0x02
,0xA1,0x02
,0x06,0xFF,0xFF
,0x09,0x74
,0x85,0x03
,0xB1,0x83
,0x09,0x74
,0x81,0x83
,0x09,0x75
,0xB1,0x83
,0x09,0x75
,0x81,0x83
,0xC0
,0x09,0xE9
,0x85,0x07
,0xB1,0x83
,0xC0 
,0xC0
,0x09,0xE0
,0x85,0xFE
,0x95,0x0A
,0x27,0xFF,0xFF,0xFF,0x7F
,0xB1,0x82
,0x09,0xE0
,0x85,0xFF
,0x95,0x3F
,0xB1,0x82
,0x05,0x84
,0x09,0x1E
,0xA1,0x84
,0x09,0x43
,0x85,0x0D
,0x75,0x10
,0x95,0x01
,0x27,0xFF,0xFF,0x00,0x00
,0x66,0x21,0xD1
,0x55,0x07
,0xB1,0x83
,0x09,0x42
,0x75,0x08
,0x26,0xFF,0x00
,0x66,0x01,0xF0
,0x55,0x00
,0xB1,0x83
,0x09,0x40
,0x85,0x12
,0x67,0x21,0xD1,0xF0,0x00
,0x55,0x07
,0xB1,0x82
,0x09,0x1F
,0x85,0x0B
,0x65,0x00
,0x55,0x00
,0xB1,0x03
,0xC0 
,0x06,0xFF,0xFF
,0x09,0x1C
,0xA1,0x00
,0x09,0x1E
,0xA1,0x81
,0x09,0x98
,0x85,0x18
,0x75,0x10
,0x27,0xFF,0xFF,0x00,0x00
,0xB1,0x83
,0x09,0x1F
,0x85,0x17
,0x75,0x08
,0x26,0xFF,0x00
,0xB1,0x03
,0xC0
,0x09,0x1E
,0xA1,0x82
,0x09,0x98
,0x85,0x18
,0x75,0x10
,0x27,0xFF,0xFF,0x00,0x00
,0xB1,0x83
,0x09,0x1F
,0x85,0x17
,0x75,0x08
,0x26,0xFF,0x00
,0xB1,0x03
,0xC0 
,0x09,0x1E
,0xA1,0x83
,0x09,0x98
,0x85,0x18
,0x75,0x10
,0x27,0xFF,0xFF,0x00,0x00
,0xB1,0x83
,0x09,0x1F
,0x85,0x17
,0x75,0x08
,0x26,0xFF,0x00
,0xB1,0x03
,0xC0
,0x09,0x1E
,0xA1,0x84
,0x09,0x98
,0x85,0x18
,0x75,0x10
,0x27,0xFF,0xFF,0x00,0x00
,0xB1,0x83
,0x09,0x1F
,0x85,0x17
,0x75,0x08
,0x26,0xFF,0x00
,0xB1,0x03
,0xC0
,0x09,0x1E
,0xA1,0x85
,0x09,0x98
,0x85,0x18
,0x75,0x10
,0x27,0xFF,0xFF,0x00,0x00
,0xB1,0x83
,0x09,0x1F
,0x85,0x17
,0x75,0x08
,0x26,0xFF,0x00
,0xB1,0x03
,0xC0
,0xC0
,0x05,0x84
,0x09,0x18
,0xA1,0x00
,0x09,0x20
,0xA1,0x81
,0x09,0x1F
,0x85,0x0B
,0xB1,0x03
,0x09,0x21
,0xB1,0x03
,0x09,0x02
,0xA1,0x02
,0x09,0x6C
,0x85,0x0C
,0xB1,0x03
,0x09,0x6B
,0x85,0x02
,0xB1,0x83
,0x09,0x6B
,0x81,0x83
,0xC0
,0x06,0xFF,0xFF
,0x09,0xE9
,0x85,0x07
,0xB1,0x83
,0xC0
,0x05,0x84
,0x09,0x20
,0xA1,0x82
,0x09,0x1F
,0x85,0x0B
,0xB1,0x03
,0x09,0x21
,0xB1,0x03
,0x09,0x02
,0xA1,0x02
,0x09,0x6C
,0x85,0x19
,0xB1,0x03
,0x09,0x6B
,0x85,0x02
,0xB1,0x83
,0x09,0x6B
,0x81,0x83
,0xC0
,0x06,0xFF,0xFF
,0x09,0xE9
,0x85,0x07
,0xB1,0x83
,0xC0
,0x05,0x84
,0x09,0x19
,0x85,0x0B
,0xB1,0x03
,0xC0
,0x09,0x16
,0xA1,0x00
,0x06,0xFF,0xFF
,0x09,0x41
,0x85,0x0C
,0xB1,0x03
,0x09,0x14
,0xA1,0x00
,0x05,0x84
,0x09,0x02
,0xA1,0x02
,0x09,0x62
,0x85,0x03
,0xB1,0x83
,0x09,0x62
,0x81,0x83
,0xC0
,0xC0
,0x09,0x1C
,0xA1,0x00
,0x09,0x54
,0x85,0x13
,0x75,0x10
,0x27,0xFF,0xFF,0x00,0x00
,0x67,0x21,0xD1,0xF0,0x00
,0x55,0x07
,0xB1,0x82
,0x09,0x53
,0x85,0x14
,0x75,0x08
,0x26,0xFF,0x00
,0xB1,0x82
,0x09,0x1D
,0x85,0x0B
,0x65,0x00
,0x55,0x00
,0xB1,0x03
,0x09,0x02
,0xA1,0x02
,0x06,0xFF,0xFF
,0x09,0x4A
,0x85,0x03
,0xB1,0x83
,0x09,0x4A
,0x81,0x83
,0xC0
,0x05,0x84
,0x09,0x30
,0x85,0x0E
,0x75,0x10
,0x27,0xFF,0xFF,0x00,0x00
,0x67,0x21,0xD1,0xF0,0x00
,0x55,0x07
,0xB1,0x83
,0xC0
,0x09,0x17
,0x85,0x0B
,0x75,0x08
,0x26,0xFF,0x00
,0x65,0x00
,0x55,0x00
,0xB1,0x03
,0xC0
,0x09,0x24
,0xA1,0x00
,0x06,0xFF,0xFF
,0x09,0x22
,0xA1,0x00
,0x09,0x98
,0x85,0x07
,0xB1,0x83
,0xC0
,0x05,0x84
,0x09,0x5A
,0x85,0x1F
,0xB1,0x82
,0x05,0x85
,0x09,0x8D
,0x85,0x0C
,0xB1,0x03
,0x09,0x2C
,0xB1,0x03
,0x06,0xFF,0xFF
,0x09,0x95
,0x85,0x15
,0xB1,0x03
,0x05,0x84
,0x09,0x57
,0x85,0x09
,0x75,0x20
,0x15,0xFF
,0x27,0xFF,0xFF,0xFF,0x7F
,0x66,0x01,0x10
,0xB1,0x82
,0x09,0x56
,0x85,0x0A
,0xB1,0x82
,0x05,0x85
,0x09,0x83
,0x85,0x0C
,0x75,0x08
,0x15,0x00
,0x26,0xFF,0x00
,0x65,0x00
,0xB1,0x03
,0x05,0x84
,0x09,0x1F
,0x85,0x0B
,0xB1,0x03
,0x05,0x85
,0x09,0x67
,0x85,0x0C
,0xB1,0x03
,0x09,0x89
,0x85,0x10
,0xB1,0x03
,0x05,0x84
,0x09,0xFD
,0xB1,0x03
,0x06,0xFF,0xFF
,0x09,0xF0
,0xB1,0x03
,0x05,0x84
,0x09,0xFE
,0xB1,0x03
,0x06,0xFF,0xFF
,0x09,0xF4
,0xB1,0x03
,0x05,0x84
,0x09,0xFF
,0xB1,0x03
,0x06,0xFF,0xFF
,0x09,0xF1
,0xB1,0x03
,0x09,0x94
,0x85,0x07
,0xB1,0x83
,0x05,0x84
,0x09,0x35
,0xB1,0x83
,0x09,0x25
,0x85,0x0B
,0xB1,0x03
,0x09,0x02
,0xA1,0x02
,0x05,0x85
,0x09,0xD0
,0x85,0x01
,0x75,0x01
,0x25,0x01
,0xB1,0x83
,0x09,0xD0
,0x81,0x83
,0x09,0x42
,0xB1,0x83
,0x09,0x42
,0x81,0x83
,0x09,0x44
,0xB1,0x83
,0x09,0x44
,0x81,0x83
,0x05,0x84
,0x09,0x73
,0xB1,0x83
,0x09,0x73
,0x81,0x83
,0x05,0x85
,0x09,0x45
,0xB1,0x83
,0x09,0x45
,0x81,0x83
,0x05,0x84
,0x09,0x61
,0xB1,0x83
,0x09,0x61
,0x81,0x83
,0x09,0x62
,0xB1,0x83
,0x09,0x62
,0x81,0x83
,0x05,0x85
,0x09,0x4B
,0xB1,0x83
,0x09,0x4B
,0x81,0x83
,0x05,0x84
,0x09,0x65
,0x75,0x08
,0x26,0xFF,0x00
,0xB1,0x83
,0x09,0x65
,0x81,0x83
,0x09,0x69
,0xB1,0x83
,0x09,0x69
,0x81,0x83
,0xC0
,0x05,0x85
,0x09,0x66
,0x85,0x06
,0xB1,0x83
,0x09,0x66
,0x81,0x83
,0x09,0x29
,0x85,0x08
,0xB1,0x83
,0x06,0xFF,0xFF
,0x09,0x4D
,0x85,0x22
,0xB1,0x82
,0x05,0x85
,0x09,0x68
,0x85,0x06
,0x75,0x20
,0x27,0xFF,0xFF,0xFF,0x7F
,0x66,0x01,0x10
,0xB1,0x83
,0x09,0x68
,0x81,0x83
,0x06,0xFF,0xFF
,0x09,0xE9
,0x85,0x07
,0x75,0x08
,0x26,0xFF,0x00
,0x65,0x00
,0xB1,0x83
,0x09,0xE2
,0x85,0x0C
,0xB1,0x03
,0xC0
,0x09,0xE5
,0xA1,0x00
,0x09,0x05
,0xA1,0x00
,0x09,0xF1
,0x85,0x10
,0xB1,0x03
,0x09,0x94
,0x85,0xFD
,0xB1,0x82
,0xC0
,0xC0
,0xC0
};

/*!< mouse report struct */
struct hid_mouse {
    uint8_t buttons;
    int8_t x;
    int8_t y;
    int8_t wheel;
};

/*!< mouse report */
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX struct hid_mouse mouse_cfg;

#define HID_STATE_IDLE 0
#define HID_STATE_BUSY 1

/*!< hid state ! Data can be sent only when state is idle  */
static volatile uint8_t hid_state = HID_STATE_IDLE;

static void usbd_event_handler(uint8_t busid, uint8_t event)
{
    switch (event) {
        case USBD_EVENT_RESET:
            break;
        case USBD_EVENT_CONNECTED:
            break;
        case USBD_EVENT_DISCONNECTED:
            break;
        case USBD_EVENT_RESUME:
            break;
        case USBD_EVENT_SUSPEND:
            break;
        case USBD_EVENT_CONFIGURED:
            hid_state = HID_STATE_IDLE;
            break;
        case USBD_EVENT_SET_REMOTE_WAKEUP:
            break;
        case USBD_EVENT_CLR_REMOTE_WAKEUP:
            break;

        default:
            break;
    }
}

/* function ------------------------------------------------------------------*/
static void usbd_hid_int_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
    hid_state = HID_STATE_IDLE;
}

/*!< endpoint call back */
static struct usbd_endpoint hid_in_ep = {
    .ep_cb = usbd_hid_int_callback,
    .ep_addr = HID_INT_EP
};

typedef struct {
    union  {
        uint8_t  Value;
        struct {
            uint8_t ACPresent                   : 1;  // 上电时置 1
            uint8_t BelowRemainingCapacityLimit : 1;
            uint8_t Charging                    : 1;  // 上电时置 1
            uint8_t CommunicationLost           : 1;
            uint8_t Discharging                 : 1;  // 断电时置 1
            uint8_t Good                        : 1;  // 上电/断电时置 1
            uint8_t InternalFailure             : 1;
            uint8_t NeedReplacement             : 1; 
        }Bits;
    }Status;
    uint8_t Overload;             // default 0
    uint8_t ShutdownImminent;    // default 0
}report_01_def;


report_01_def report_01 = {
.Status = {
     .Bits.ACPresent                   = 1
    ,.Bits.BelowRemainingCapacityLimit = 0
    ,.Bits.Charging                    = 1
    ,.Bits.CommunicationLost           = 0
    ,.Bits.Discharging                 = 0
    ,.Bits.Good                        = 1
    ,.Bits.InternalFailure             = 0
    ,.Bits.NeedReplacement             = 0
}
,.Overload = 0
,.ShutdownImminent = 0
};                    

typedef  struct __PACKED{
    uint8_t  RemainingCapacity; // byte 1  10~100
    uint32_t RunTimeToEmpty;    // max = 0x7FFF FFFF   0x0000 0E10 = 3600  byte[0]=0x10
}report_06_def ;

report_06_def report_06 = {
    .RemainingCapacity  = 100,
    .RunTimeToEmpty     = 3600,
};

uint32_t report_cnt;
uint8_t is_ac_lost;

void usbd_hid_get_report(uint8_t busid, uint8_t intf, uint8_t report_id, uint8_t report_type, uint8_t **data, uint32_t *len)
{
    report_cnt++;
    
    *len = 0;
    
    if(is_ac_lost)
    {
        report_01.Status.Bits.ACPresent   = 0;
        report_01.Status.Bits.Charging    = 0;
        report_01.Status.Bits.Discharging = 1;
        
        
        if(report_06.RemainingCapacity > 10) {
            report_06.RemainingCapacity--;
        }
    }
    else {
        report_01.Status.Bits.ACPresent   = 1;
        report_01.Status.Bits.Charging    = 1;
        report_01.Status.Bits.Discharging = 0;
        report_06.RemainingCapacity = 100;
    }
    
    if(intf == 0) { 
        
        uint8_t *pdata = *data;
        memset(pdata, 0, 64);
        int32_t i = 0;
        switch (report_id) {
            case 0x0C: {
                pdata[i++] = 0x0C;
                pdata[i++] = 0x01;
                pdata[i++] = 0x01;
                pdata[i++] = 0x01;
                pdata[i++] = 0x02;
                pdata[i++] = 0x64;
                pdata[i++] = 0x64;
                pdata[i++] = 0x04;
                *len = 64;
            }
            break;
        
            case 0x10: {
                pdata[i++] = 0x10;
                pdata[i++] = 0x05;
                pdata[i++] = 0x01;
                pdata[i++] = 0x0D;
                pdata[i++] = 0x03;
                pdata[i++] = 0x07;
                pdata[i++] = 0x04;
                pdata[i++] = 0x06;
                pdata[i++] = 0x08;
                *len = 64;
            }
            break;
            case 0x08: {
                pdata[i++] = 0x08;
                pdata[i++] = 0x05;
                pdata[i++] = 0x01;
                pdata[i++] = 0x0D;
                pdata[i++] = 0x03;
                pdata[i++] = 0x07;
                pdata[i++] = 0x04;
                pdata[i++] = 0x06;
                pdata[i++] = 0x08;
                *len = 64;
            }
            break;
                     
            case 0x01: {
                pdata[i++] = 0x01;
                pdata[i++] = report_01.Status.Value;
                pdata[i++] = report_01.Overload;
                pdata[i++] = report_01.ShutdownImminent;
                pdata[i++] = 0;
                pdata[i++] = 0;
                pdata[i++] = 0x04;
                pdata[i++] = 0x06;
                pdata[i++] = 0x08;
                *len = 64;
            }
            break;
    
            case 0x06: {
                pdata[i++] = 0x06;
                
                
                
                pdata[i++] = report_06.RemainingCapacity;
                memcpy(&pdata[i], (const void*)&report_06.RunTimeToEmpty, sizeof(report_06.RunTimeToEmpty));
                i += sizeof(report_06.RunTimeToEmpty);
                pdata[i++] = 0x04;
                pdata[i++] = 0x06;
                pdata[i++] = 0x08;
                *len = 64;
            }
            break;

            default: {
        
            }
            break;
        }
    }
    
}

struct usbd_interface intf0;
// usbd_get_descriptor
// usbd_event_ep0_setup_complete_handler  CONFIG_USBDEV_REQUEST_BUFFER_LEN
void hid_mouse_init(uint8_t busid, uintptr_t reg_base)
{
    usbd_desc_register(busid, hid_descriptor);
    usbd_add_interface(busid, usbd_hid_init_intf(busid, &intf0, hid_mouse_report_desc, sizeof(hid_mouse_report_desc)));   // 
    usbd_add_endpoint(busid, &hid_in_ep);

    usbd_initialize(busid, reg_base, usbd_event_handler);

    /*!< init mouse report data */
    mouse_cfg.buttons = 0;
    mouse_cfg.wheel = 0;
    mouse_cfg.x = 0;
    mouse_cfg.y = 0;
}

#define CURSOR_STEP  2U
#define CURSOR_WIDTH 20U

void draw_circle(uint8_t *buf)
{
    static int32_t move_cnt = 0;
    static uint8_t step_x_y = 0;
    static int8_t x = 0, y = 0;

    move_cnt++;
    if (move_cnt > CURSOR_WIDTH) {
        step_x_y++;
        step_x_y = step_x_y % 4;
        move_cnt = 0;
    }
    switch (step_x_y) {
        case 0: {
            y = 0;
            x = CURSOR_STEP;

        } break;

        case 1: {
            x = 0;
            y = CURSOR_STEP;

        } break;

        case 2: {
            y = 0;
            x = (int8_t)(-CURSOR_STEP);

        } break;

        case 3: {
            x = 0;
            y = (int8_t)(-CURSOR_STEP);

        } break;
    }

    buf[0] = 0;
    buf[1] = x;
    buf[2] = y;
    buf[3] = 0;
}

/* https://cps-check.com/cn/polling-rate-check */
void hid_mouse_test(uint8_t busid)
{
    if(usb_device_is_configured(busid) == false) {
        return;
    }

    int counter = 0;
    while (counter < 1000) {
        draw_circle((uint8_t *)&mouse_cfg);
        hid_state = HID_STATE_BUSY;
        usbd_ep_start_write(busid, HID_INT_EP, (uint8_t *)&mouse_cfg, 4);
        while (hid_state == HID_STATE_BUSY) {
        }

        counter++;
    }
}
